package com.acme.domain.account;

import com.acme.exceptions.NoEnoughFundsException;
import com.acme.exceptions.OverDraftLimitExceededException;

public class CheckingAccount extends AbstractAccount {

    private double overdraft;

    public CheckingAccount(final int id, final double amount,
                           final double overdraft) {
        super(id, amount);
        this.overdraft = overdraft;
    }

    @Override
    public void withdraw(final double amount) throws NoEnoughFundsException {
        if (amount < 0) {
            throw new IllegalArgumentException("Amount can not be negative");
        }
        if (this.balance - amount >= -overdraft) {
            this.balance -= amount;
        } else {
            throw new NoEnoughFundsException(amount);
        }

        if (this.balance < amount) {
            // Not enough balance to cover the amount requested to withdraw
            // Check if there is enough in the overdraft protection (if any)
            double overdraftNeeded = amount - this.balance;
            if (overdraft < overdraftNeeded) {
                throw new OverDraftLimitExceededException(overdraftNeeded
                        - overdraft);
            } else {
                // Yes, there is overdraft protection and enough to cover the
                // amount
                this.balance = 0.0;
                overdraft -= overdraftNeeded;
            }
        } else {
            // Yes, there is enough balance to cover the amount
            // Proceed as usual
            this.balance = this.balance - amount;
        }


    }

    @Override
    public void deposit(final double amount) {
        if (amount > 0) {
            this.balance += amount;
        } else {
            throw new IllegalArgumentException("amount ca not be negative");
        }

    }

    public AccountType getAccountType() {
        return AccountType.CHECKING;
    }

    public double getOverdraft() {
        return overdraft;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        CheckingAccount that = (CheckingAccount) o;
        //XXX [MY] Comparison of business keys (id) enough
        if (Double.compare(that.balance, balance) != 0) return false;
        if (Double.compare(that.overdraft, overdraft) != 0) return false;
        if (id != that.id) return false;
        if (state != that.state) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = id;
        long temp = balance != +0.0d ? Double.doubleToLongBits(balance) : 0L;
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = overdraft != +0.0d ? Double.doubleToLongBits(overdraft) : 0L;
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (state != null ? state.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "CheckingAccount{" +
                "id=" + id +
                ", balance=" + balance +
                ", state=" + state +
                ", overdraft=" + overdraft +
                '}';
    }
}
